home *** CD-ROM | disk | FTP | other *** search
/ Your Choice 3 / Your Choice Software Collection 3.iso / prgmming / pcl4pb42 / xymodem.bas < prev    next >
BASIC Source File  |  1994-10-03  |  11KB  |  443 lines

  1. ' -- XYMODEM.BAS --
  2. '
  3. ' This program is donated to the Public
  4. ' Domain by MarshallSoft Computing, Inc.
  5. ' It is provided as an example of the use
  6. ' of the Personal Communications Library.
  7. '
  8. $CPU 8086          'make compatible with XT systems
  9. $LIB ALL OFF       'turn off all PowerBASIC libraries
  10. $ERROR ALL ON      'turn on all PowerBASIC error checking
  11. $OPTIMIZE SIZE     'optimize for smaller code
  12. $COMPILE UNIT      'compile to a UNIT (.PBU)
  13.  
  14. DEFINT A-Z         'Required for all numeric functions, forces PB to not
  15.                    'include floating point routines in UNIT (makes it smaller)
  16.  
  17. $INCLUDE "PCL4PB.BI"
  18. $INCLUDE "TERM_IO.BI"
  19. $INCLUDE "XYPACKET.BI"
  20.  
  21. %NAK   = &H15
  22. %CAN   = &H18
  23. %FALSE = 0
  24. %TRUE  = NOT %FALSE
  25.  
  26. DEFINT A-Z
  27.  
  28. FUNCTION FetchName(Filename AS STRING) PUBLIC
  29.  
  30.   FetchName = %TRUE
  31.   IF LEN(Filename$) = 0 THEN
  32.     WriteMsg "Enter filename: ", 1
  33.     ReadMsg Filename$, 16, 20
  34.     IF LEN(Filename) = 0 THEN
  35.       FetchName = %FALSE
  36.     END IF
  37.   END IF
  38.  
  39. END FUNCTION
  40.  
  41. FUNCTION RxyModem(BYVAL Port      AS INTEGER, _
  42.                         Filename  AS STRING,  _
  43.                   BYVAL NCGbyte   AS BYTE,    _
  44.                   BYVAL BatchFlag AS INTEGER) PUBLIC
  45.  
  46.   ON LOCAL ERROR GOTO RxyTrap
  47.  
  48.   DIM Buffer(1024) AS BYTE
  49.   DIM TheByte      AS BYTE
  50.   DIM BufferSize   AS INTEGER
  51.   DIM ErrorFlag    AS INTEGER
  52.   DIM EOTflag      AS INTEGER
  53.   DIM FirstPacket  AS INTEGER
  54.   DIM Code         AS INTEGER
  55.   DIM FileNbr      AS INTEGER
  56.   DIM Packet       AS INTEGER
  57.   DIM PacketNbr    AS INTEGER
  58.   DIM I            AS INTEGER
  59.   DIM Flag         AS INTEGER
  60.   DIM FileBytes    AS LONG
  61.   DIM AnyKey       AS STRING
  62.   DIM Message      AS STRING
  63.   DIM Temp         AS STRING
  64.  
  65.   ErrorFlag = %FALSE
  66.   EOTflag   = %FALSE
  67.  
  68.   WriteMsg "XYMODEM Receive: Waiting for Sender ", 1
  69.  
  70.   'clear comm port
  71.   Code = SioRxFlush(Port)
  72.  
  73.   'Send NAKs or 'C's
  74.   IF NOT RxStartup(Port, NCGbyte) THEN
  75.     RxyModem = %FALSE
  76.     EXIT FUNCTION
  77.   END IF
  78.  
  79.   'open file unless BatchFlag is on
  80.   IF BatchFlag THEN
  81.     FirstPacket = 0
  82.   ELSE
  83.     FirstPacket = 1
  84.     'Open file for write
  85.     FileNbr = FREEFILE
  86.     OPEN Filename$ FOR BINARY ACCESS WRITE AS FileNbr
  87.     PRINT "Opening "; Filename$
  88.   END IF
  89.  
  90.   'get each packet in turn
  91.   FOR Packet = FirstPacket TO 32767
  92.     'user aborts ?
  93.     AnyKey$ = INKEY$
  94.     IF AnyKey$ = STR$(%CAN) THEN
  95.       CALL TxCAN(Port)
  96.       CALL WriteMsg("*** Canceled by USER ***", 1)
  97.       RxyModem = %FALSE
  98.       EXIT FUNCTION
  99.     END IF
  100.     'issue message
  101.     Message$ = "Packet " + STR$(Packet)
  102.     CALL WriteMsg(Message$, 1)
  103.     PacketNbr = Packet AND 255
  104.     'get next packet
  105.     IF NOT RxPacket(Port, Packet, Buffer(), BufferSize, NCGbyte, EOTflag) THEN
  106.       RxyModem = %FALSE
  107.       EXIT FUNCTION
  108.     END IF
  109.     'packet 0 ?
  110.     IF Packet = 0 THEN
  111.       'name & date packet
  112.       IF Buffer(0) = 0 THEN
  113.         CALL WriteMsg("Batch transfer complete", 1)
  114.         RxyModem = %TRUE
  115.         EXIT FUNCTION
  116.       END IF
  117.       'construct filename
  118.       I = 0
  119.       Filename$ = ""
  120.       DO
  121.         TheByte = Buffer(I)
  122.         IF TheByte = 0 THEN
  123.           EXIT DO
  124.         END IF
  125.         Filename$ = Filename$ + CHR$(TheByte)
  126.         I = I + 1
  127.       LOOP
  128.       'get file size
  129.       I = I + 1
  130.       Temp$ = ""
  131.       DO
  132.         TheByte = Buffer(I)
  133.         IF TheByte = 0 THEN
  134.           EXIT DO
  135.         END IF
  136.         Temp$ = Temp$ + CHR$(TheByte)
  137.         I = I + 1
  138.       LOOP
  139.       FileBytes = VAL(Temp$)
  140.     END IF
  141.     'all done if EOT was received
  142.     IF EOTflag THEN
  143.       CLOSE FileNbr
  144.       CALL WriteMsg("Transfer completed", 1)
  145.       RxyModem = %TRUE
  146.       EXIT FUNCTION
  147.     END IF
  148.     'process the packet
  149.     IF Packet = 0 THEN
  150.       'open file using filename in packet 0
  151.       FileNbr = FREEFILE
  152.       OPEN Filename$ FOR BINARY ACCESS WRITE AS FileNbr
  153.       PRINT "Opening "; Filename$
  154.       'must restart after packet 0
  155.       Flag = RxStartup(Port, NCGbyte)
  156.     ELSE
  157.       'Packet > 0  ==> write Buffer
  158.       FOR I = 0 TO BufferSize-1
  159.         PUT FileNbr, , Buffer(I)
  160.       NEXT I
  161.     END IF
  162.   NEXT Packet
  163.  
  164.   CLOSE FileNbr
  165.   EXIT FUNCTION
  166.  
  167. RxyTrap:
  168.   SELECT CASE ERR
  169.     CASE 53
  170.       Message$ = "Cannot open " + Filename$ + " for write"
  171.       CALL WriteMsg(Message$, 1)
  172.     CASE ELSE
  173.       PRINT "RX Error: "; "(ERROR$)" ; " ("; ERR; ")"
  174.     END SELECT
  175.  
  176.     RxyModem = %FALSE
  177.     EXIT FUNCTION
  178.  
  179. END FUNCTION
  180.  
  181. FUNCTION TxyModem(BYVAL Port      AS INTEGER, _
  182.                         Filename  AS STRING,  _
  183.                   BYVAL OneKflag  AS INTEGER, _
  184.                   BYVAL BatchFlag AS INTEGER) PUBLIC
  185.   ON LOCAL ERROR GOTO TxyTrap
  186.  
  187.   DIM Buffer(1024)   AS BYTE
  188.   DIM NCGbyte        AS BYTE
  189.   DIM TheByte        AS BYTE
  190.   DIM BufferSize     AS INTEGER
  191.   DIM ErrorFlag      AS INTEGER
  192.   DIM EOTflag        AS INTEGER
  193.   DIM FirstPacket    AS INTEGER
  194.   DIM Code           AS INTEGER
  195.   DIM FileNbr        AS INTEGER
  196.   DIM Packet         AS INTEGER
  197.   DIM PacketNbr      AS INTEGER
  198.   DIM ReadSize       AS INTEGER
  199.   DIM I              AS INTEGER
  200.   DIM K              AS INTEGER
  201.   DIM L              AS INTEGER
  202.   DIM EmptyFlag      AS INTEGER
  203.   DIM Flag           AS INTEGER
  204.   DIM BlockSize      AS INTEGER
  205.   DIM Number128      AS WORD
  206.   DIM Number1K       AS WORD
  207.   DIM FileBytes      AS LONG
  208.   DIM RemainingBytes AS LONG
  209.   DIM AnyKey         AS STRING
  210.   DIM Message        AS STRING
  211.   DIM Temp           AS STRING
  212.  
  213.   Number128 = 0
  214.   Number1K  = 0
  215.   NCGbyte   = %NAK
  216.   EOTflag   = %FALSE
  217.   EmptyFlag = %FALSE
  218.  
  219.   IF BatchFlag THEN
  220.     IF LEN(Filename$) = 0 THEN
  221.       EmptyFlag = %TRUE
  222.     END IF
  223.   END IF
  224.   IF NOT EmptyFlag THEN
  225.     FileNbr = FREEFILE
  226.     OPEN Filename$ FOR BINARY ACCESS READ AS FileNbr
  227.     PRINT "Opening "; Filename$
  228.   END IF
  229.   WriteMsg "XYMODEM: waiting for receiver ", 1
  230.  
  231.   'compute # blocks
  232.   IF EmptyFlag THEN
  233.     'empty file
  234.     Number128 = 0
  235.     Number1K = 0
  236.   ELSE
  237.     'filename is not empty. compute file length
  238.     FileBytes = LOF(FileNbr)
  239.     RemainingBytes = FileBytes
  240.     IF OneKflag THEN
  241.       Number1K = FileBytes \ 1024
  242.     ELSE
  243.       Number1K = 0
  244.     END IF
  245.     Number128 = (FileBytes - 1024 * Number1K) \ 128
  246.     IF (128 * Number128 + 1024 * Number1K) < FileBytes THEN
  247.       Number128 = Number128 + 1
  248.     END IF
  249.     Message$ = STR$(Number1K) + " 1K & " + STR$(Number128) + " 128-byte packets"
  250.     WriteMsg Message$, 1
  251.     PRINT Message$
  252.   END IF
  253.  
  254.   'clear comm port (there may be several NAKs queued up)
  255.   Code = SioRxFlush(Port)
  256.  
  257.   'get receivers start up NAK or 'C'
  258.   IF NOT TxStartup(Port, NCGbyte) THEN
  259.     TxyModem = %FALSE
  260.     EXIT FUNCTION
  261.   END IF
  262.  
  263.   'loop over all packets
  264.   IF BatchFlag THEN
  265.     FirstPacket = 0
  266.   ELSE
  267.     FirstPacket = 1
  268.   END IF
  269.  
  270.   'transmit each packet in turn
  271.   FOR Packet = FirstPacket TO Number1K + Number128
  272.     'user aborts ?
  273.     AnyKey$ = INKEY$
  274.     IF AnyKey$ = STR$(%CAN) THEN
  275.       CALL TxCAN(Port)
  276.       CALL WriteMsg("*** Canceled by USER ***", 1)
  277.       TxyModem = %FALSE
  278.       EXIT FUNCTION
  279.     END IF
  280.     'issue message
  281.     Message$ = "Packet " + STR$(Packet)
  282.     CALL WriteMsg(Message$, 1)
  283.     'load up internal buffer
  284.     IF Packet = 0 THEN
  285.       'packet = 0. Init Buffer to 128 zeros.
  286.       BlockSize = 128
  287.       FOR I = 0 TO 127
  288.         Buffer(I) = 0
  289.       NEXT I
  290.       IF EmptyFlag THEN
  291.         'send empty buffer
  292.       ELSE
  293.         'not empty: copy filename to buffer
  294.         K = 0
  295.         L = LEN(Filename$)
  296.         FOR I = 1 TO L
  297.           Buffer(K) = ASC(MID$(Filename$,I,1))
  298.           K = K + 1
  299.         NEXT I
  300.         'copy file length to buffer
  301.         Temp$ = STR$(FileBytes)
  302.         L = LEN(Temp$)
  303.         K = K + 1
  304.         FOR I = 1 TO L
  305.           Buffer(K) = ASC(MID$(Temp$,I,1))
  306.           K = K + 1
  307.         NEXT I
  308.       END IF
  309.     ELSE
  310.       'DATA Packet: use 1K or 128-byte blocks ?
  311.       IF BatchFlag AND (Packet <= Number1K) THEN
  312.         BlockSize = 1024
  313.       ELSE
  314.         BlockSize = 128
  315.       END IF
  316.       'compute # bytes to read
  317.       IF RemainingBytes < BlockSize THEN
  318.         ReadSize = RemainingBytes
  319.       ELSE
  320.         ReadSize = BlockSize
  321.       END IF
  322.       'read next block from disk
  323.       FOR I = 0 TO ReadSize-1
  324.         GET FileNbr, , Buffer(I)
  325.       NEXT I
  326.       RemainingBytes = RemainingBytes - ReadSize
  327.       'pad short buffer with ^Z
  328.       IF ReadSize < BlockSize THEN
  329.         FOR I = ReadSize TO BlockSize-1
  330.           Buffer(I) = &H1A
  331.         NEXT I
  332.       END IF
  333.     END IF
  334.     'Send this packet
  335.     IF NOT TxPacket(Port, Packet, Buffer(), BlockSize, NCGbyte) THEN
  336.       TxyModem = %FALSE
  337.       EXIT FUNCTION
  338.     END IF
  339.     Code = SioDelay(5)
  340.     'must 'restart' after non null packet 0
  341.     IF (NOT EmptyFlag) AND (Packet = 0) THEN
  342.       Flag = TxStartup(Port, NCGbyte)
  343.     END IF
  344.   NEXT Packet
  345.  
  346.   'done if empty packet 0
  347.   IF EmptyFlag THEN
  348.     CALL WriteMsg("Batch transfer completed", 1)
  349.     TxyModem = %TRUE
  350.     EXIT FUNCTION
  351.   END IF
  352.  
  353.   'all done. send EOT up to 10 times
  354.   IF NOT TxEOT(Port) THEN
  355.     PRINT "EOT not acknowledged"
  356.     TxyModem = %FALSE
  357.     EXIT FUNCTION
  358.   END IF
  359.  
  360.   CLOSE FileNbr
  361.   CALL WriteMsg("Transfer completed", 1)
  362.   TxyModem = %TRUE
  363.   EXIT FUNCTION
  364.  
  365. TxyTrap:
  366.   SELECT CASE ERR
  367.     CASE 52
  368.       Message$ = "Cannot open " + Filename$ + " for read"
  369.       WriteMsg Message$, 1
  370.     CASE ELSE
  371.       PRINT "TX Error: "; "(ERROR$)" ; " ("; ERR; ")"
  372.     END SELECT
  373.     TxyModem = %FALSE
  374.     EXIT FUNCTION
  375.  
  376. END FUNCTION
  377.  
  378. FUNCTION XmodemRx(BYVAL Port     AS INTEGER, _
  379.                         Filename AS STRING,  _
  380.                   BYVAL NCGbyte  AS BYTE)    PUBLIC
  381.  
  382.   IF FetchName(Filename$) THEN
  383.     XmodemRx = RxyModem(Port, Filename$, NCGbyte, %FALSE)
  384.   ELSE
  385.     XmodemRx = %FALSE
  386.   END IF
  387.  
  388. END FUNCTION
  389.  
  390. FUNCTION XmodemTx(BYVAL Port     AS INTEGER, _
  391.                         Filename AS STRING,  _
  392.                   BYVAL OneKflag AS INTEGER) PUBLIC
  393.  
  394.   IF FetchName(Filename$) THEN
  395.     XmodemTx = TxyModem(Port, Filename$, OneKflag, %FALSE)
  396.   ELSE
  397.     XmodemTx = %FALSE
  398.   END IF
  399.  
  400. END FUNCTION
  401.  
  402. FUNCTION YmodemRx(BYVAL Port     AS INTEGER, _
  403.                         Filename AS STRING,  _
  404.                   BYVAL NCGbyte  AS BYTE)    PUBLIC
  405.  
  406.   DIM AnyKey AS STRING
  407.  
  408.   YmodemRx = %TRUE
  409.   DO
  410.     AnyKey$ = INKEY$
  411.     IF AnyKey$ <> "" THEN
  412.       WriteMsg "Aborted by user", 1
  413.       EXIT DO
  414.     END IF
  415.     WriteMsg "Ready for next file", 1
  416.     Filename$ = ""
  417.     IF NOT RxyModem(Port, Filename$, NCGbyte, %TRUE) THEN
  418.       YmodemRx = %FALSE
  419.       EXIT FUNCTION
  420.     END IF
  421.     'empty filename ?
  422.     IF Filename$ = "" THEN
  423.       EXIT FUNCTION
  424.     END IF
  425.   LOOP
  426.  
  427. END FUNCTION
  428.  
  429. FUNCTION YmodemTx(BYVAL Port     AS INTEGER,  _
  430.                         Filename AS STRING,   _
  431.                   BYVAL OneKflag AS INTEGER)  PUBLIC
  432.  
  433.   IF FetchName(Filename$) THEN
  434.     YmodemTx = TxyModem(Port, Filename$, OneKflag, %TRUE)
  435.     'send empty filename to terminate
  436.     Filename$ = ""
  437.     YmodemTx = TxyModem(Port, Filename$, OneKflag, %TRUE)
  438.   ELSE
  439.     YmodemTx = %FALSE
  440.   END IF
  441.  
  442. END FUNCTION
  443.